﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;


namespace CMWA.Packager.Tools.Bytes
{

    public class cptCrypting
    {
        private Byte[] GetBytesFromPassword()
        {
            return Convert.FromBase64String("a4ndawOTGYtIm4RniM7u6Q==");
        }

        public byte[] GetRegistrationKeyBytes(string productKey)
        {
            return RegistrationKeys.GetRegistrationKeyBytes(productKey);
        }


        string password = "";

        private static byte[] EncryptExtracted()
        {
            return new byte[]
        		            {
        		                0x49, 0x76, 0x61, 0x6e,
        		                0x20, 0x4d, 0x65, 0x64,
        		                0x76, 0x65, 0x64, 0x65,
        		                0x76, 0xaa, 0x12, 0x13 };
        }

        internal byte[] GetPassword(int type, string key)
        {
            if (type == 0) return GetBytesFromPassword();

            return GetRegistrationKeyBytes(key);
        }

        #region Reading files
        public Stream ReadFromStream(Stream s, string key, int type)
        {
            byte[] b = GetPassword(type, key);
            return DecryptStream(s, b, EncryptExtracted());
        }

        public Stream WriteFromStream(Stream s, string key, int type)
        {
            byte[] b = GetPassword(type, key);
            return DecryptStream(s, b, EncryptExtracted());
        }

        public byte[] ReadFile(string fn, string key, int type)
        {
            byte[] b = GetPassword(type, key);
            return ReadFile(fn, b);
        }

        public byte[] ReadFile(string fn, byte[] bytes)
        {
            int len = (int)new FileInfo(fn).Length;
            Byte[] b = new Byte[len];
            FileStream fs = File.OpenRead(fn);
            fs.Read(b, 0, len);
            Byte[] boutput = new Byte[len];
            boutput = Decrypt(b, bytes, EncryptExtracted());
            return boutput;
        }
        #endregion

        #region Writing Files
        public byte[] WriteFile(string fn, string output, string key, int type)
        {
            byte[] b = GetPassword(type, key);;
            return WriteFile(fn, output, b);
        }

        internal byte[] WriteFile(string fn, string output, byte[] bytes)
        {
            int len = (int)new FileInfo(fn).Length;
          //  int nlen = (int)(Math.Ceiling((double)len / 16)) * 16;
            Byte[] b = new Byte[len];
            Byte[] boutput;

            FileStream fs = File.OpenRead(fn);
            fs.Read(b, 0, len);

            boutput = Encrypt(b, bytes, EncryptExtracted());

            FileStream outp = File.OpenWrite(output);
            outp.Write(boutput, 0, boutput.Length);
            outp.Close();
            return b;
        }
        #endregion

        #region Reading and Writing Bytes
        private Stream WriteStream(Stream s,
                                byte[] Key, byte[] IV)
        {


            Rijndael alg = RijndaelManaged.Create();
            alg.BlockSize = 128;
            alg.Key = Key;
            alg.IV = IV;
            alg.Padding = PaddingMode.Zeros;

            int x = 0;
            CryptoStream cs = new CryptoStream(s,
                alg.CreateEncryptor(), CryptoStreamMode.Write);

            return cs;
        }

        private Stream DecryptStream(Stream s,
                                byte[] Key, byte[] IV)
        {


            Rijndael alg = RijndaelManaged.Create();
            alg.BlockSize = 128;
            alg.Key = Key;
            alg.IV = IV;
            alg.Padding = PaddingMode.Zeros;

            int x = 0;
            CryptoStream cs = new CryptoStream(s,
                alg.CreateDecryptor(), CryptoStreamMode.Read);
            return cs;
        }

        private byte[] Encrypt(byte[] clearData, byte[] Key, byte[] IV)
        {
            MemoryStream ms = new MemoryStream();
            Rijndael alg = RijndaelManaged.Create();
            alg.BlockSize = 128;
            alg.Key = Key;
            alg.IV = IV;
            alg.Padding = PaddingMode.Zeros;


            using (CryptoStream cs = new CryptoStream(ms,
               alg.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(clearData, 0, clearData.Length);
                cs.FlushFinalBlock();
            }

            byte[] encryptedData = ms.ToArray();
            
            return encryptedData;
        }

        private byte[] Decrypt(byte[] cipherData,
                                byte[] Key, byte[] IV)
        {
            byte[] decryptedData = new byte[cipherData.Length]; 

            MemoryStream ms = new MemoryStream(decryptedData);

            Rijndael alg = RijndaelManaged.Create();
            alg.BlockSize = 128;
            alg.Key = Key;
            alg.IV = IV;
            alg.Padding = PaddingMode.Zeros;


            int x = 0;
            using (CryptoStream cs = new CryptoStream(ms,
                alg.CreateDecryptor(), CryptoStreamMode.Read))
            {
                x++; 
                int read=  cs.Read(cipherData, 0, cipherData.Length);
            }
            

            return decryptedData;
        }

        #endregion
    }
}
